package org.example.service;

import org.example.entity.Device;
import org.example.entity.DeviceControlLog;
import org.example.repository.DeviceRepository;
import org.example.repository.DeviceControlLogRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * 设备服务类
 * 提供智能家居设备管理的各项功能
 */
@Service
@Transactional
public class DeviceService {

    @Autowired
    private DeviceRepository deviceRepository;

    @Autowired
    private DeviceControlLogRepository deviceControlLogRepository;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 创建设备
     * @param device 设备信息
     * @return 保存后的设备对象
     */
    public Device createDevice(Device device) {
        return deviceRepository.save(device);
    }

    /**
     * 根据ID查找设备
     * @param id 设备ID
     * @return 设备对象（可能为空）
     */
    @Transactional(readOnly = true)
    public Optional<Device> findById(Long id) {
        return deviceRepository.findById(id);
    }

    /**
     * 根据用户ID查找设备
     * @param userId 用户ID
     * @return 用户设备列表
     */
    public List<Device> findByUserId(Long userId) {
        try {
            System.out.println("DeviceService.findByUserId - 用户ID: " + userId);
            List<Device> devices = deviceRepository.findByUserId(userId);
            System.out.println("DeviceService.findByUserId - 找到设备: " + (devices != null ? devices.size() : "null"));
            return devices;
        } catch (Exception e) {
            System.err.println("DeviceService.findByUserId 失败: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("获取用户设备失败: " + e.getMessage());
        }
    }

    /**
     * 根据房间查找设备
     * @param userId 用户ID
     * @param room 房间名称
     * @return 指定房间的设备列表
     */
    @Transactional(readOnly = true)
    public List<Device> findByUserIdAndRoom(Long userId, String room) {
        return deviceRepository.findByUserIdAndRoom(userId, room);
    }

    /**
     * 根据设备类型查找设备
     * @param userId 用户ID
     * @param deviceTypeId 设备类型ID
     * @return 指定类型的设备列表
     */
    @Transactional(readOnly = true)
    public List<Device> findByUserIdAndDeviceTypeId(Long userId, Long deviceTypeId) {
        return deviceRepository.findByUserIdAndDeviceTypeId(userId, deviceTypeId);
    }

    /**
     * 根据状态查找设备
     * @param userId 用户ID
     * @param status 设备状态
     * @return 指定状态的设备列表
     */
    @Transactional(readOnly = true)
    public List<Device> findByUserIdAndStatus(Long userId, Integer status) {
        return deviceRepository.findByUserIdAndStatus(userId, status);
    }

    /**
     * 根据在线状态查找设备
     * @param userId 用户ID
     * @param isOnline 在线状态（0-离线，1-在线）
     * @return 指定在线状态的设备列表
     */
    @Transactional(readOnly = true)
    public List<Device> findByUserIdAndIsOnline(Long userId, Integer isOnline) {
        return deviceRepository.findByUserIdAndIsOnline(userId, isOnline);
    }

    /**
     * 根据设备名称搜索
     * @param userId 用户ID
     * @param name 设备名称关键词
     * @return 匹配的设备列表
     */
    @Transactional(readOnly = true)
    public List<Device> searchDevicesByName(Long userId, String name) {
        return deviceRepository.findByUserIdAndNameContaining(userId, name);
    }

    /**
     * 获取用户所有房间
     * @param userId 用户ID
     * @return 用户拥有的房间列表
     */
    @Transactional(readOnly = true)
    public List<String> getUserRooms(Long userId) {
        return deviceRepository.findDistinctRoomsByUserId(userId);
    }

    /**
     * 更新设备信息
     * @param device 包含更新信息的设备对象
     * @return 更新后的设备对象
     */
    public Device updateDevice(Device device) {
        Device existingDevice = deviceRepository.findById(device.getId())
                .orElseThrow(() -> new RuntimeException("设备不存在"));

        if (device.getName() != null) {
            existingDevice.setName(device.getName());
        }
        if (device.getRoom() != null) {
            existingDevice.setRoom(device.getRoom());
        }
        if (device.getProperties() != null) {
            existingDevice.setProperties(device.getProperties());
        }

        return deviceRepository.save(existingDevice);
    }

    /**
     * 控制设备开关 - 使用原生SQL避免锁冲突
     * @param deviceId 设备ID
     * @param userId 用户ID
     * @param status 目标状态
     * @param action 操作描述
     * @return 控制后的设备信息
     */
    public Device controlDevice(Long deviceId, Long userId, Integer status, String action) {
        try {
            System.out.println("开始控制设备 - ID: " + deviceId + ", 用户: " + userId + ", 状态: " + status);

            // 先检查设备是否存在
            String checkSql = "SELECT d.id, d.status, d.device_type_id, dt.name as device_type_name " +
                             "FROM devices d JOIN device_types dt ON d.device_type_id = dt.id WHERE d.id = ?";
            List<Object[]> results = jdbcTemplate.query(checkSql, (rs, rowNum) ->
                new Object[]{rs.getLong("id"), rs.getInt("status"),
                           rs.getLong("device_type_id"), rs.getString("device_type_name")}, deviceId);

            if (results.isEmpty()) {
                throw new RuntimeException("设备不存在");
            }

            Object[] deviceInfo = results.get(0);
            Long deviceTypeId = (Long) deviceInfo[2];
            String deviceTypeName = (String) deviceInfo[3];

            // 检查用户是否有权限控制此类型设备
            String permissionSql = "SELECT COUNT(*) FROM devices WHERE device_type_id = ? AND user_id = ?";
            int userDeviceCount = jdbcTemplate.queryForObject(permissionSql, Integer.class, deviceTypeId, userId);

            // 对于摄像头类型，允许用户控制任何摄像头设备
            // 对于其他类型，只有当用户有该类型的设备时才允许控制
            if ("智能摄像头".equals(deviceTypeName) || userDeviceCount > 0) {
                Integer oldStatus = (Integer) results.get(0)[1];
                System.out.println("设备当前状态: " + oldStatus + ", 目标状态: " + status);

                // 使用原生SQL直接更新，避免Hibernate锁问题
                String updateSql = "UPDATE devices SET status = ?, updated_at = NOW() WHERE id = ?";
                int updatedRows = jdbcTemplate.update(updateSql, status, deviceId);

                if (updatedRows == 0) {
                    throw new RuntimeException("设备状态更新失败");
                }

                System.out.println("设备状态更新成功");

                // 异步记录控制日志
                new Thread(() -> {
                    try {
                        String insertLogSql = "INSERT INTO device_control_logs " +
                                            "(device_id, user_id, action, old_status, new_status, ip_address, control_time) " +
                                            "VALUES (?, ?, ?, ?, ?, ?, NOW())";
                        jdbcTemplate.update(insertLogSql, deviceId, userId, action,
                                         oldStatus.toString(), status.toString(), "127.0.0.1");
                        System.out.println("控制日志记录成功");
                    } catch (Exception logException) {
                        System.err.println("保存控制日志失败: " + logException.getMessage());
                    }
                }).start();

                // 返回更新后的设备信息
                return deviceRepository.findById(deviceId).orElse(null);
            } else {
                throw new RuntimeException("用户没有权限控制此设备");
            }
        } catch (Exception e) {
            System.err.println("设备控制失败: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("设备控制失败: " + e.getMessage());
        }
    }

    /**
     * 更新设备在线状态
     * @param deviceId 设备ID
     * @param isOnline 在线状态（0-离线，1-在线）
     * @return 更新后的设备对象
     */
    public Device updateDeviceOnlineStatus(Long deviceId, Integer isOnline) {
        Device device = deviceRepository.findById(deviceId)
                .orElseThrow(() -> new RuntimeException("设备不存在"));

        device.setIsOnline(isOnline);
        return deviceRepository.save(device);
    }

    /**
     * 更新设备属性
     * @param deviceId 设备ID
     * @param properties 设备属性JSON字符串
     * @return 更新后的设备对象
     */
    public Device updateDeviceProperties(Long deviceId, String properties) {
        try {
            System.out.println("DeviceService.updateDeviceProperties - 设备ID: " + deviceId);
            System.out.println("DeviceService.updateDeviceProperties - 属性内容: " + properties);

            Device device = deviceRepository.findById(deviceId)
                    .orElseThrow(() -> new RuntimeException("设备不存在"));

            System.out.println("找到设备: " + device.getName() + ", 当前属性: " + device.getProperties());

            device.setProperties(properties);
            device.setUpdatedAt(java.time.LocalDateTime.now());

            Device updatedDevice = deviceRepository.saveAndFlush(device);
            System.out.println("设备属性更新成功: " + updatedDevice.getName());
            return updatedDevice;
        } catch (Exception e) {
            System.err.println("设备属性更新失败: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("设备属性更新失败: " + e.getMessage());
        }
    }

    /**
     * 统计用户设备数量
     * @param userId 用户ID
     * @return 设备数量
     */
    @Transactional(readOnly = true)
    public long countDevicesByUserId(Long userId) {
        return deviceRepository.countByUserId(userId);
    }

    /**
     * 统计在线设备数量
     * @param userId 用户ID
     * @return 在线设备数量
     */
    @Transactional(readOnly = true)
    public long countOnlineDevicesByUserId(Long userId) {
        return deviceRepository.countOnlineDevicesByUserId(userId);
    }

    /**
     * 获取设备控制记录
     * @param deviceId 设备ID
     * @return 设备控制记录列表
     */
    @Transactional(readOnly = true)
    public List<DeviceControlLog> getDeviceControlLogs(Long deviceId) {
        return deviceControlLogRepository.findByDeviceId(deviceId);
    }

    /**
     * 分页获取设备控制记录
     * @param deviceId 设备ID
     * @param pageable 分页参数
     * @return 分页的设备控制记录
     */
    @Transactional(readOnly = true)
    public Page<DeviceControlLog> getDeviceControlLogs(Long deviceId, Pageable pageable) {
        return deviceControlLogRepository.findByDeviceId(deviceId, pageable);
    }

    /**
     * 删除设备
     * @param deviceId 设备ID
     */
    public void deleteDevice(Long deviceId) {
        if (!deviceRepository.existsById(deviceId)) {
            throw new RuntimeException("设备不存在");
        }
        deviceRepository.deleteById(deviceId);
    }
    
    /**
     * 获取所有设备（管理员专用）
     * @return 所有设备列表
     */
    @Transactional(readOnly = true)
    public List<Device> findAllDevices() {
        return deviceRepository.findAll();
    }
}
